Contents

  1. You want to do what?!?
  2. Getting started
  3. The desktop
  4. A pseudo-base class
  5. Joy and grief
  6. Timing is everything (or sometimes nothing)
  7. Conclusions / Lessons Learned

Setting up

The desktop is modeled as an instance of Window. It can contain other objects, but also has to coordinate screen updates.
// Import just about everything...
import java.awt.*;
import java.awt.event.*;
import java.awt.image.*;
import java.io.*;
import java.net.*;
import java.util.*;
import com.sun.java.swing.*;

public class Desktop extends Window implements Serializable, MouseListener, MouseMotionListener, TimerEventListener {
	// Most attribute values we don't want saved, so they're marked transient.
	transient boolean bSplash = false, firstRepaint = true, dragInProgress = false;

	transient int delay;
	transient int menuBarHeight;
	transient int res;
	transient int IMG_SPLASH = 0;
	transient int IMG_APPLE = 1;
	transient int IMG_TRASH = 2;
	transient int IMG_TRASH_FULL = 3;
	// snip

	transient static int activeMenu = -1, activeMenuItem = -1;

	transient DesktopMenuBar dmb;
	transient DesktopImage imgSplash, imgFolder, imgDriveMask, imgTrashStatic, imgTrash, imgTrashMask, imgTrashFull, imgTrashFullMask, imgDrive, imgApple;
		
	transient Rectangle activeMenuRect = new Rectangle( -1, -1, 0, 0 );

	transient Toolkit tk = Toolkit.getDefaultToolkit();

	Vector vectorImages = new Vector();
	static Vector vectorWindows = new Vector();

	Desktop() {
		// General setup.
		super( new Frame() );
		this.setLayout( null );
		this.setBackground( Color.lightGray );
		this.menuFont = new Font( "Dialog", Font.BOLD, 12 );
		this.iconFont = new Font( "SansSerif", Font.PLAIN, 12 );
		this.setFont( this.menuFont );

		// Initialize instance variables.
		this.fileSep = Global.fileSep;
		this.bSplash = true;
		imgSplash = new DesktopImage();
		imgApple = new DesktopImage();
		imgTrash = new DesktopImage();
		
		MediaTracker mt = new MediaTracker( this );
		URL u;

		// Get splash image.
		try {
			u = this.getClass().getResource( Global.splashString );
			imgSplash.setImage( this.createImage( ( ImageProducer )( u.getContent() ) ) );
			mt.addImage( imgSplash.getImage(), IMG_SPLASH );

			mt.waitForID( IMG_SPLASH );

			imgSplash.setX( this.getX() + ( ( this.getWidth() / 2 ) - ( imgSplash.getImage().getWidth( this ) / 2 ) ) );
			imgSplash.setY( this.getY() + ( ( this.getHeight() / 2 ) - ( imgSplash.getImage().getHeight( this ) / 2 ) ) );
		}
		// Not doing anything useful with the exceptions, but need to know when they occur.
		catch ( MalformedURLException e ) {
			System.out.println( "MalformedURLException" );
		}
		catch ( IOException e ) {
			System.out.println( "IOException" );
		}
		catch ( InterruptedException e ) {
			System.out.println( "InterruptedException" );
		}

		// Set Window properties based on screen size.
		res = tk.getScreenResolution();
		d = tk.getScreenSize();
		this.setBounds( Global.defaultX, Global.defaultY, d.width, d.height );

		// Not setup to dynamically handle screen resolution changes.
		this.setMenuBarHeight( Global.defaultMenuBarHeight );

		this.setVisible( true );
		this.setBackground( Color.lightGray );

		// Display splash screen.
		this.repaint();
		mt.removeImage( imgSplash.getImage(), IMG_SPLASH );

		// Get all images.
		try {
			u = this.getClass().getResource( Global.appleString );
			imgApple.setImage( this.createImage( ( ImageProducer )( u.getContent() ) ) );
			mt.addImage( imgApple.getImage(), IMG_APPLE );

			u = this.getClass().getResource( Global.trashString );
			imgTrash.setImage( this.createImage( ( ImageProducer )( u.getContent() ) ) );
			mt.addImage( imgTrash.getImage(), IMG_TRASH );

			// blah, blah, blah

			mt.waitForAll();

			// Set coords and labels.
			imgApple.setX( this.getX() + ( 2 * Global.defaultMenuHSep ) );
			imgApple.setY( this.getY() + Global.defaultMenuItemVSep );

			imgTrash.setX( this.getX() + this.getWidth() - ( imgTrash.getImage().getWidth( this ) * 2 ) );
			imgTrash.setY( this.getY() + this.getHeight() - ( imgTrash.getImage().getHeight( this ) * 3 ) );
			imgTrash.setLabel( Global.trashDisplayString );
			imgTrash.setLabelLocation( imgTrash.getX() + ( imgTrash.getImage().getWidth( this ) / 2 ) - ( this.getGraphics().getFontMetrics().stringWidth( imgTrash.getLabel() ) / 2 ), imgTrash.getY() + ( imgTrash.getImage().getHeight( this ) ) + ( this.getGraphics().getFontMetrics().getHeight() ) );
			
			imgDrive.setX( this.getX() + this.getWidth() - ( imgDrive.getImage().getWidth( this ) * 2 ) );
			imgDrive.setY( this.getY() + this.menuBarHeight + imgDrive.getImage().getHeight( this ) );

			// The following volume stuff doesn't have to be in the try{} block.  Oh well.

			String defaultVolume = System.getProperty( "user.home" );
			
			int loc = 0;

			// Parse the volume name.
			StringBuffer sb2 = new StringBuffer();
			sb2.append( defaultVolume.charAt( 0 ) );
			int len = defaultVolume.length();
			int m = 0;
			while ( ++m < len ) {
				sb2.append( defaultVolume.charAt( m ) );

				if ( ( defaultVolume.charAt( m ) == Global.sep02 ) || ( defaultVolume.charAt( m ) == Global.sep01 ) )
					break;
			}

			sb2 = new StringBuffer();
			len = defaultVolume.length();
			m = 0;
			while ( m < len ) {
				if ( ( defaultVolume.charAt( m ) != Global.sep02 ) && ( defaultVolume.charAt( m ) != Global.sep01 ) )
					sb2.append( defaultVolume.charAt( m ) );

				m++;
			}
			
			defaultVolume = sb2.toString();
			
			// Volume name includes first '%20'.
			// Rework this for MacOS.
			loc = defaultVolume.indexOf( Global.spaceSep );

			while ( ( loc >= 0 ) && ( loc < defaultVolume.length() ) ) {
				String s1 = new String( defaultVolume.substring( 0, loc ) );
				String s2 = new String( defaultVolume.substring( loc + Global.spaceSep.length() ) );
				defaultVolume = new String( s1 + " " + s2 );
				loc = defaultVolume.indexOf( Global.spaceSep );
			}

			imgDrive.setLabel( defaultVolume );
			imgDrive.setLabelLocation( imgDrive.getX() + ( imgDrive.getImage().getWidth( this ) / 2 ) - ( this.getGraphics().getFontMetrics().stringWidth( imgDrive.getLabel() ) / 2 ), imgDrive.getY() + ( imgDrive.getImage().getHeight( this ) ) + ( this.getGraphics().getFontMetrics().getHeight() ) );

//			this.doDelay();
		}
		catch ( MalformedURLException e ) {
			System.out.println( "MalformedURLException" );
		}
		// blah, blah, blah

		vectorImages.addElement( imgTrash );
		vectorImages.addElement( imgDrive );

		// Hold static images for all docs and folders.
		vectorUtil.addElement( imgDoc );
		vectorUtil.addElement( imgFolder );

		DesktopDoc.setImage( imgDoc.getImage() );
		DesktopFolder.setImage( imgFolder.getImage() );

		// Initialize the trash.
		if ( !this.checkTrashExists() )
			this.createTrashDir();
		
		// If the trash is full, set the proper icon.
		DesktopImage di = ( ( DesktopImage )this.vectorImages.elementAt( 0 ) );
		String path = di.getPath();
		File f = new File( path );
		if ( f.exists() ) {
			String array[] = f.list();
				
			if ( ( array != null ) && ( array.length > 0 ) )
				this.vectorImages.setElementAt( this.imgTrashFull, 0 );
		}

		this.imgTrashFull.setPath( di.getPath() );

		this.restoreState();

		this.setupMenuBar();

		// Setup event listeners.
		this.addMouseListener( ( MouseListener )this );
		this.addMouseMotionListener( ( MouseMotionListener )this );
		
		this.bSplash = false;
		this.repaint();
	}
PreviousNext